﻿using System;
using System.Threading.Tasks;
using Loong.Domain.Uow;
using Loong.Threading.Locks;

namespace Loong.BackgroundJobs
{
    public class BackgroundJobStore : IBackgroundJobStore
    {
        private readonly IUnitOfWorkManager _unitOfWorkManager;
        private readonly IBackgroundJobDbAccessor _backgroundJobDbAccessor;
        private readonly ILockFactory _lockFactory;

        public BackgroundJobStore(
            IUnitOfWorkManager unitOfWorkManager,
            IBackgroundJobDbAccessor backgroundJobDbAccessor,
            ILockFactory lockFactory)
        {
            _unitOfWorkManager = unitOfWorkManager;
            _backgroundJobDbAccessor = backgroundJobDbAccessor;
            _lockFactory = lockFactory;
        }

        public async Task<BackgroundJobInfo> GetAndLockWaitingJobAsync()
        {
            using (await _lockFactory.LockAsync("GetAndLockWaitingJob", _lockFactory.GetOrCreateOwner()))
            {
                using (var uow = _unitOfWorkManager.Begin())
                {
                    var waitingJob = await _backgroundJobDbAccessor.GetWaitingJobAsync();

                    if (waitingJob != null)
                    {
                        waitingJob.LockEndTime = DateTime.Now.AddMinutes(30);
                        await _backgroundJobDbAccessor.LockJobAsync(waitingJob);
                    }

                    await uow.CompleteAsync();

                    return waitingJob;
                }
            }
        }

        public async Task InsertJobAsync(BackgroundJobInfo jobInfo)
        {
            await _backgroundJobDbAccessor.InsertAsync(jobInfo);
        }

        public async Task UpdateJobAsync(BackgroundJobInfo jobInfo)
        {
            using (var uow = _unitOfWorkManager.Begin())
            {
                await _backgroundJobDbAccessor.UpdateAsync(jobInfo);

                await uow.CompleteAsync();
            }
        }

        public async Task DeleteJobAsync(long jobId)
        {
            await _backgroundJobDbAccessor.DeleteAsync(j => j.Id == jobId);
        }

        public async Task DeleteJobAsync(BackgroundJobInfo jobInfo)
        {
            using (var uow = _unitOfWorkManager.Begin())
            {
                await _backgroundJobDbAccessor.DeleteAsync(jobInfo);

                await uow.CompleteAsync();
            }
        }
    }
}
